/***********************************************************************

	This file is part of KEEL-software, the Data Mining tool for regression, 
	classification, clustering, pattern mining and so on.

	Copyright (C) 2004-2010
	
	F. Herrera (herrera@decsai.ugr.es)
    L. Sánchez (luciano@uniovi.es)
    J. Alcalá-Fdez (jalcala@decsai.ugr.es)
    S. García (sglopez@ujaen.es)
    A. Fernández (alberto.fernandez@ujaen.es)
    J. Luengo (julianlm@decsai.ugr.es)

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see http://www.gnu.org/licenses/
  
**********************************************************************/

package keel.Algorithms.Neural_Networks.NNEP_Common;


import keel.Algorithms.Neural_Networks.NNEP_Common.initiators.IInitiator;
import keel.Algorithms.Neural_Networks.NNEP_Common.neuralnet.ILayer;
import keel.Algorithms.Neural_Networks.NNEP_Common.neuralnet.INeuralNet;
import keel.Algorithms.Neural_Networks.NNEP_Common.neuralnet.INeuron;
import net.sf.jclec.ISpecies;
import net.sf.jclec.base.AbstractCreator;

import org.apache.commons.lang.builder.EqualsBuilder;

/**
 * <p> Creation of NeuralNetIndividual (and subclasses).
 * @author Written by Pedro Antonio Gutierrez Penia (University of Cordoba) 16/7/2007
 * @author Written by Aaron Ruiz Mora (University of Cordoba) 16/7/2007
 * @param <I> Type of individuals in population
 * @version 0.1
 * @since JDK1.5
 * </p>
 */

public class NeuralNetCreator<I extends NeuralNetIndividual> extends AbstractCreator<I>
{
	/**
	 * <p>
	 * Creation of NeuralNetIndividual (and subclasses).
	 * </p>
	 */
	/////////////////////////////////////////////////////////////////
	// --------------------------------------- Serialization constant
	/////////////////////////////////////////////////////////////////
	
	/** Generated by Eclipse */
	
	private static final long serialVersionUID = -2638928425169895614L;
	
	/////////////////////////////////////////////////////////////////
	// ------------------------------- Internal (operation) variables
	/////////////////////////////////////////////////////////////////
	
	/** Associated species */
	
	protected INeuralNetSpecies<I> species;
	
	/** Initiators of weights */
	
	protected IInitiator [] initiators;
	
	/////////////////////////////////////////////////////////////////
	// ------------------------------------------------- Constructors
	/////////////////////////////////////////////////////////////////
	
	/**
	 * <p>
	 * Empty constructor
	 * </p>
	 */
	
	public NeuralNetCreator() {
		super();
	}
	
	/////////////////////////////////////////////////////////////////
	// -------------------------- Overwriting AbstractCreator methods
	/////////////////////////////////////////////////////////////////
	
	/**
	 * <p>
	 * Prepares the creation initiators
	 * </p>
	 */
	protected void prepareCreation() {
		ISpecies<I> spc = context.getSpecies();
		if (spc instanceof INeuralNetSpecies) {
			// Sets individual species
			this.species = (INeuralNetSpecies<I>) spc;
		}
		else
			throw new IllegalStateException("Illegal species in context");
		
		// Generate the initiators of layers of neural nets
		initiators = new IInitiator[species.getNOfHiddenLayers()+1];
		try {			
			//Each hidden Layer initiator
			for(int i=0; i<species.getNOfHiddenLayers(); i++){
				initiators[i] = (IInitiator) Class.forName(species.getHiddenLayerInitiator(i)).newInstance();
				initiators[i].contextualize(context);
			}
			
			//Output Layer initiator
			initiators[species.getNOfHiddenLayers()] = (IInitiator) Class.forName(species.getOutputLayerInitiator()).newInstance();
			initiators[species.getNOfHiddenLayers()].contextualize(context);
			
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}
	
    /**
     * <p>
     * Creates the next individual
     * </p>
     */
	protected void createNext() {
		// Create Genotype
		INeuralNet genotype = species.createGenotype();
		
		// Initiate neural net
		initiateNeuralNet(genotype);
		
		// Create individual with the neural net
		I individual = species.createIndividual(genotype);
		
		// Add to the buffer
		createdBuffer.add(individual);
	}
	
	/////////////////////////////////////////////////////////////////
	// ---------------------------------------------- Private methods
	/////////////////////////////////////////////////////////////////
	
	/**
	 * <p>
	 * Initiate a neural net
	 * 
	 * @param neuralNet Neural net to initiate
	 * <p>
	 */
	
	private void initiateNeuralNet(INeuralNet neuralNet){
		//Init hiddenLayers
		ILayer<? extends INeuron> previousLayer = neuralNet.getInputLayer();
		for(int i=0; i<neuralNet.getNofhlayers(); i++){
			initiators[i].initiate(neuralNet.getHlayer(i), previousLayer, i, 0);
			previousLayer = neuralNet.getHlayer(i);
		}

        //Init outputLayer
		initiators[neuralNet.getNofhlayers()].initiate(neuralNet.getOutputLayer(), previousLayer, neuralNet.getNofhlayers(), 0);
	}
	
	/////////////////////////////////////////////////////////////////
	// --------------------------- Overwrite java.lang.Object methods
	/////////////////////////////////////////////////////////////////
	
	/**
	 * <p>
	 * Compares creators
	 * @param other Creator
	 * @return True if the comparison is equal
	 * </p>
	 */
	public boolean equals(Object other)
	{
		if (other instanceof NeuralNetCreator){
			NeuralNetCreator nother = (NeuralNetCreator) other;
			EqualsBuilder eb = new EqualsBuilder();
			//TODO eb.append(evaluate, nother.evaluate);
			eb.append(randgen, nother.randgen);
			return eb.isEquals();
		}
		else {
			return false;
		}
	}
	
}

